# -*- coding: utf-8 -*-
import networkx as nx
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import json
import sys
from math import sqrt
from model import anagraphdistance

class StorageDistance:
    def __init__(self, node_list = [], algorithm_type = 1):
        self.node_list      = node_list
        self.ana_distance   = anagraphdistance.AnagraphDistance()

        self.setDistanceAlgorithm(algorithm_type)

    def setDistanceAlgorithm(self, algorithm_type):
        if algorithm_type in [1, 2, 3, 4]:
            self.algorithm_type = algorithm_type

            self.ana_distance.setAlgorithmType(algorithm_type)

    def setNodeList(self, node_list):
        self.node_list = node_list

    def storeDistance(self, min_index, max_index):
        # 先删除旧数据
        self.ana_distance.flushDistance()

        tmp_name_list = []
        # 计算所有的方剂之间的集合距离，并存入mongoDB
        for node_item_1 in self.node_list:
            tmp_name_list.append(node_item_1['name'])

            for node_item_2 in self.node_list:
                if node_item_2['name'] not in tmp_name_list and node_list.index(node_item_2) >= min_index and node_list.index(node_item_2) <= max_index:
                    distance = self.__calculateDistance(node_item_1, node_item_2)
                    self.ana_distance.setDistance(node_item_1['name'], node_item_2['name'], distance)

    def __calculateDistance(self, vector_1, vector_2):
        if self.algorithm_type == 1:
            vec_1 = np.array(vector_1['vector'])
            vec_2 = np.array(vector_2['vector'])

            # 1.euclidean distance
            distance = np.sqrt(np.sum(np.square(vec_1 - vec_2)))
        elif self.algorithm_type == 2:
            vec_1 = np.array(vector_1['vector'])
            vec_2 = np.array(vector_2['vector'])

            # 2.cosine similarity
            den = (np.sqrt(vec_1.dot(vec_1))) * (np.sqrt(vec_2.dot(vec_2)))
            if den == 0:
                distance = 1.0
            else:
                distance = 1.0 - (vec_1.dot(vec_2)) / den
        elif self.algorithm_type == 3:
            # 3.Jaccard distance
            insect_names    = list(set(vector_1['medicines']) & set(vector_2['medicines']))
            union_names     = list(set(vector_1['medicines']) | set(vector_2['medicines']))
            if len(union_names) > 0:
                distance        = 1.0 - float(len(insect_names)) / len(union_names)
            else:
                distance        = 1.0
        elif self.algorithm_type == 4:
            # 4. pearson correlation coefficient
            vec_1 = vector_1['vector']
            vec_2 = vector_2['vector']

            length = len(vec_1)

            sum1 = sum(vec_1)
            sum2 = sum(vec_2)

            sqSum1 = sum([pow(item_1, 2) for item_1 in vec_1])
            sqSum2 = sum([pow(item_2, 2) for item_2 in vec_2])

            pSum = sum([vec_1[index] * vec_2[index] for index in range(len(vec_1))])

            num = pSum - (sum1 * sum2 / length)
            den = sqrt((sqSum1 - pow(sum1, 2) / length) * (sqSum2 - pow(sum2, 2) / length))

            if den == 0:
                return 1.0

            return 1.0 - num / den
        else:
            print 'set algorithm type error, make sure value in [1(euclidean distance), 2(cosine similarity), 3(degree),]' + '\n'

        return self.__exchangeDistance(distance)

    def __exchangeDistance(self, distance):
        distance = np.power(distance, 1.0)
        return distance
